package it.unibo.refolding.pico.stripchart;

import it.unibo.refolding.common.MyRuntimeException;

import java.util.ArrayList;
import java.util.List;

import com.google.common.base.Function;

public class Repeater<F, T> implements Runnable {
  
  private final Function<F, T> function;
  private F in;
  private boolean finishRequested;
  private boolean finished;
  private final List<T> results;

  public Repeater(Function<F, T> function) {
    this.function = function;
    results = new ArrayList<>();
  }
  
  public void run() {
    while (true) {
      F localIn;
      synchronized (this) {
        if (finishRequested) {
          finished = true;
          notifyAll();
          break;
        }
        if (in == null) {
          try {
            wait();
            continue;
          } catch (InterruptedException e) {
            throw new MyRuntimeException(e.getMessage(), e);
          }
        } else {
          localIn = in;
        }
      }
      T t = function.apply(localIn);
      synchronized (this) {
        results.add(t);
      }
    }
  }
  
  public List<T> exchange(F in) {
    List<T> a = new ArrayList<>();
    synchronized (this) {
      this.in = in;
      a.addAll(results);
      results.clear();
      notifyAll();
    }
    return a;
  }

  public void change(F in) {
    synchronized (this) {
      this.in = in;
      notifyAll();
    }
  }

  public List<T> finish() {
    synchronized (this) {
      this.finishRequested = true;
      notifyAll();
      while (!finished) {
        try{
          wait();
        } catch (InterruptedException e) {
          throw new MyRuntimeException(e.getMessage(), e);
        }
      }
    }
    List<T> a = new ArrayList<>();
    synchronized (this) {
      a.addAll(results);
      results.clear();
    }
    return a;
  }
}
